home *** CD-ROM | disk | FTP | other *** search
/ The World's Largest Collection of Windows Software / The World's Largest Collection of Windows Software - Disc 1.iso / connect / _j2 / wsmtpd16 / net.c < prev    next >
C/C++ Source or Header  |  1993-10-09  |  17KB  |  635 lines

  1. /* NET.C - Network window procedure for WSMTPSRV
  2.          - WinSock V1.1 required
  3.  
  4.    Author: Ian Blenke
  5.  
  6. Ian Blenke cannot be held responsible for damages, expressed or implied, for
  7. the use of this software. No commercial use can be made of this product
  8. without the consent of the author. No profit of any kind can be made on the
  9. sale or distribution of this program. If you wish to distribute this program
  10. with other samples of WinSock programming, you must first contact the author
  11. so that he can keep accurate records of its usage. If you write any programs
  12. based on this source code, you may not sell them for any profit without the
  13. written consent of the author. If you incorporate this source code into a
  14. public domain program, all the author requires is a notification that "part
  15. of the code was written by Ian Blenke" and some form of notification that
  16. his name was used in the public domain software distribution. This does not
  17. represent a contract on the part of the author. If any issues cannot clearly
  18. be resolved by reading this text, immediately contact the author.
  19.  
  20. If you have any bug reports and/or source patches... By all means, tell me! I
  21. would be glad to help keep this code up to date. Do not, however, modify this
  22. source in any way and re-distribute it without the author's knowledge. This
  23. would constitute something not-good.
  24.  
  25. I don't like such agreements, but in today's world of lawyers and lawbreakers
  26. I have little other choice. Enjoy!
  27. */
  28.  
  29. #ifndef NET_C
  30. #define NET_C
  31. #include "Net.H"
  32. #include "Dialogs.h"
  33.  
  34. #include <Time.h>  // DOS Time functions for netGetTimeAndDate()
  35.  
  36.  
  37. /* BOOL netInit(void);
  38.     Purpose: To initialize the network window
  39.     Given:   Nothing.
  40.     Returns: TRUE if an error occured.
  41. */
  42. BOOL netInit(void)
  43. {
  44.  WNDCLASS wndclass;
  45.  SOCKADDR_IN saMain;
  46.  LPSERVENT lpseServEnt;
  47.  LPHOSTENT lpheHostEnt;
  48.  BOOL bDebug;
  49.  
  50.  if(gethostname((LPSTR)szLocalHostName,
  51.                 sizeof(szLocalHostName)) == SOCKET_ERROR)
  52.  {
  53.     // We need SOME valid name - make it "Unknown"
  54.   lstrcpy((LPSTR)szLocalHostName, (LPSTR)STRING_UNKNOWN);
  55.  }
  56.  else
  57.  {
  58.   lpheHostEnt=gethostbyname((LPSTR)szLocalHostName);
  59.   if(lpheHostEnt!=NULL)
  60.   {
  61.    lstrcpy((LPSTR)szLocalHostName, lpheHostEnt->h_name);
  62.   }
  63.  }
  64.  
  65.  lstrcpy((LPSTR)szNetworkClass, (LPSTR)CLASS_NETWORK);
  66.  
  67.  wndclass.style         = 0;
  68.  wndclass.lpfnWndProc   = (WNDPROC)NetProc;
  69.  wndclass.cbClsExtra    = 0;
  70.  wndclass.cbWndExtra    = 0;
  71.  wndclass.hInstance     = hInst;
  72.  wndclass.hIcon         = NULL;
  73.  wndclass.hCursor       = NULL;
  74.  wndclass.hbrBackground = NULL;
  75.  wndclass.lpszMenuName  = NULL;
  76.  wndclass.lpszClassName = (LPSTR)szNetworkClass;
  77.  
  78.  if(!RegisterClass(&wndclass))
  79.  {
  80.   return(TRUE);
  81.  }
  82.  
  83.     // Create the main "invisible" network window
  84.  hWndMain=CreateWindow((LPSTR)szNetworkClass,
  85.                       (LPSTR)"",
  86.                       WS_CHILD,
  87.                       CW_USEDEFAULT, CW_USEDEFAULT,
  88.                       CW_USEDEFAULT, CW_USEDEFAULT,
  89.                       hWndDlg, NULL, hInst, NULL);
  90.  
  91.  if(!hWndMain)
  92.  {
  93.   UnregisterClass((LPSTR)szNetworkClass, hInst);
  94.   return(TRUE);
  95.  }
  96.  
  97.  sSocketMain=socket(AF_INET, SOCK_STREAM, 0);
  98.  if(sSocketMain==SOCKET_ERROR)
  99.  {
  100.   netError();
  101.   DestroyWindow(hWndMain);
  102.   UnregisterClass((LPSTR)szNetworkClass, hInst);
  103.   return(TRUE);
  104.  }
  105.  
  106.  lpseServEnt=getservbyname((LPSTR)SMTP_NAME, NULL);
  107.  if(lpseServEnt==NULL)
  108.  {
  109.   saMain.sin_port=htons(SMTP_PORT);
  110.  }
  111.  else
  112.  {
  113.   saMain.sin_port=lpseServEnt->s_port;
  114.  }
  115.  
  116.  saMain.sin_family=AF_INET;     // Address Family type Internet
  117.  saMain.sin_addr.s_addr=0;      // Bind to local host
  118.  
  119.  if(bind(sSocketMain, (LPSOCKADDR)&saMain,
  120.          sizeof(saMain))==SOCKET_ERROR)
  121.  {
  122.   netError();
  123.   DestroyWindow(hWndMain);
  124.   closesocket(sSocketMain);
  125.   UnregisterClass((LPSTR)szNetworkClass, hInst);
  126.   return(TRUE);
  127.  }
  128.  
  129.  if(listen(sSocketMain, MAXCLIENTS)==SOCKET_ERROR)
  130.  {
  131.   netError();
  132.   DestroyWindow(hWndMain);
  133.   closesocket(sSocketMain);
  134.   UnregisterClass((LPSTR)szNetworkClass, hInst);
  135.   return(TRUE);
  136.  }
  137.  
  138.         // Make the main socket non-blocking, and set up
  139.         // the connection message.
  140.  if(WSAAsyncSelect(sSocketMain, hWndMain, NET_ACTIVITY,
  141.     FD_READ | FD_WRITE | FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR)
  142.  {
  143.   netError();
  144.   DestroyWindow(hWndMain);
  145.   closesocket(sSocketMain);
  146.   UnregisterClass((LPSTR)szNetworkClass, hInst);
  147.   return(TRUE);
  148.  }
  149.  
  150.  bDebug=TRUE;
  151.  setsockopt(sSocketMain,
  152.             SOL_SOCKET, SO_DEBUG, (char FAR *)&bDebug,
  153.             sizeof(bDebug));
  154.  setsockopt(sSocketMain,
  155.             IPPROTO_TCP, SO_DEBUG, (char FAR *)&bDebug,
  156.             sizeof(bDebug));
  157.  
  158.     // ALL sockets are accounted for with structures
  159.     // Even the main one - to get the NetProc to work right.
  160.  smtpAddClient(sSocketMain);
  161.  return(FALSE);
  162. } /* netInit() */
  163.  
  164.  
  165. /* void netError(void);
  166.     Purpose: To tell the user something broke.
  167.     Given:   Nothing.
  168.     Returns: Nothing.
  169.     Uses:    netErrorTable, WSAGetLastError(), smtpError()
  170. */
  171. void netError(void)
  172. {
  173.  int iError;
  174.  int iIndex;
  175.  
  176.  iIndex=0;
  177.  iError=WSAGetLastError();
  178.  if((iError==WSAEWOULDBLOCK)||
  179.     (iError==WSAENOTCONN) ||
  180.     (iError==WSANO_DATA))       // Why does v1.09beta tell me this?
  181.     return;
  182.  while(netErrorTable[iIndex].iError!=0)
  183.  {
  184.   if(netErrorTable[iIndex].iError==iError)
  185.   {
  186.    smtpError(netErrorTable[iIndex].iResourceID);
  187.    return;
  188.   }
  189.   iIndex++;
  190.  }
  191.  return;
  192. } /* netError */
  193.  
  194.  
  195. /* void netClose(void);
  196.     Purpose: To close the network portion of WSMTPSRV
  197.     Given:   Nothing.
  198.     Returns: Nothing.
  199. */
  200. void netClose(void)
  201. {
  202.  if(hWndMain)
  203.  {
  204.   smtpDestroyClient(smtpClientsHead);
  205.   smtpClientsHead=NULL;
  206.   DestroyWindow(hWndMain);
  207.   UnregisterClass((LPCSTR)szNetworkClass, hInst);
  208.   hWndMain=0;
  209.  }
  210.  WSACleanup();
  211.  return;
  212. } /* netClose */
  213.  
  214.  
  215. /* BOOL CALLBACK NetProc(HWND, UINT, WPARAM, LPARAM);
  216.     Purpose: To handle all Windows Sockets messages.
  217.     Given:   Standard CALLBACK args.
  218.     Returns: FALSE if we handled it.
  219. */
  220. LRESULT CALLBACK NetProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  221. {
  222.     // First thing we do is get the connection's window
  223.  LPSMTPCLIENT lpClient;
  224.  SOCKET sSocket;
  225. #ifdef USE_TITLE
  226.  char szTitle[MAXLINE];
  227. #endif /* USE_TITLE */
  228.  int           iAddrSize;
  229.  SOCKADDR_IN   saPeer;
  230.  LPSOCKADDR_IN lpsaHostAddr;
  231.  LPHOSTENT     lpheHostEnt;
  232.  char          szTime[40];
  233.  
  234.  if(wParam!=0) lpClient=smtpSocketToClient((SOCKET)wParam);
  235.  else lpClient=NULL;
  236.  
  237.  if(lpClient)      // If it isn't a Client message - ignore it
  238.  {
  239.   switch(Msg)
  240.   {
  241.    case NET_ACTIVITY:
  242.    {
  243.     // This is the handler for the main network window
  244.     switch(WSAGETSELECTEVENT(lParam))
  245.     {
  246.      case FD_ACCEPT:
  247.      {
  248.           // Get a pending accept
  249.       iAddrSize=sizeof(SOCKADDR_IN);
  250.       sSocket=accept(sSocketMain,
  251.                      (LPSOCKADDR)&saPeer,
  252.                      (int FAR *)&iAddrSize);
  253.       if(sSocket==INVALID_SOCKET) return(FALSE);
  254.  
  255.           // Allocate socket specific data
  256.       lpClient=smtpAddClient(sSocket);
  257.  
  258.       if(!lpClient) return(FALSE);
  259.  
  260.           // Remember the connected Peer's address
  261.       lpClient->saPeer=saPeer;
  262.           // Get the Peer's Name asyncronously
  263.       lpsaHostAddr=(LPSOCKADDR_IN)&(lpClient->saPeer);
  264.  
  265.       lpheHostEnt= gethostbyaddr((LPSTR)&(lpsaHostAddr->sin_addr.s_addr),
  266.                                  4, PF_INET);
  267.       if(lpheHostEnt==NULL)
  268.       {     // Ah HA! No sneaking in!
  269.        lstrcpy((LPSTR)lpClient->szPeer,
  270.                  inet_ntoa(lpsaHostAddr->sin_addr));
  271.       }
  272.       else
  273.       {
  274.        lstrcpy((LPSTR)lpClient->szPeer,
  275.             (LPSTR)(lpheHostEnt->h_name));
  276.       }
  277.       smtpLog(LOG_HIGH | LOG_TIME, LOG_CONNECT_S,
  278.               (LPSTR)lpClient->szPeer);
  279.  
  280.       netGetTimeAndDate((LPSTR)szTime, sizeof(szTime));
  281.  
  282.       /* Set the window title (for debugging)  */
  283. #ifdef USE_TITLE
  284.       if(iLogLevel==LOG_HIGH)
  285.       {
  286.        wsprintf((LPSTR)szTitle, "WSMTPD - Connect: from %s:%d",
  287.                 (LPSTR)lpClient->szPeer,
  288.                 lpClient->saPeer.sin_port);
  289.        SetWindowText(hWndDlg, (LPSTR)szTitle);
  290.       }
  291. #endif /* USE_TITLE */
  292.  
  293.       smtpSendMessage(lpClient, 220, MSG_I_AM_S_S,
  294.                       (LPSTR)szLocalHostName,
  295.                       (LPSTR)szTime);
  296.  
  297.         // Not all stacks support this yet.
  298. /*      if(WSAAsyncGetHostByAddr(hWnd, NET_NAME,
  299.                 (LPSTR)&(lpsaHostAddr->sin_addr.s_addr),
  300.                 4, PF_INET,
  301.                 (LPSTR)lpClient->hePeer,
  302.                 MAXGETHOSTSTRUCT) != 0)
  303.       {
  304.        return(FALSE);
  305.       }   /**/
  306.             // Make sure that the name can be found
  307.       netError();
  308.       PostMessage(hWnd, NET_NAME, 0, WSAMAKEASYNCREPLY(0 ,1));
  309.       return(FALSE);
  310.      }
  311.  
  312.      // WinSock received something for us
  313.      case FD_READ:
  314.      {
  315.       int iError;
  316.  
  317.         // FIFO log it
  318.       iError=netReceiveData(lpClient);
  319.       if(iError==0)
  320.       { // It closed!?!
  321.        smtpDestroyClient(lpClient);
  322.        return(FALSE);
  323.       }
  324.       else if(iError==SOCKET_ERROR)
  325.       { // Miscellaneous Error
  326.        netError();
  327.        return(FALSE);
  328.       }
  329.         // Call the server routines
  330.       (void)smtpServer(lpClient);
  331.         // We handled the event, return FALSE
  332.       return(FALSE);
  333.      }
  334.      break; /* FD_READ */
  335.  
  336.      // WinSock is ready to send
  337.      case FD_WRITE:
  338.      { // FIFO log it
  339.       if(netSendData(lpClient)==SOCKET_ERROR)
  340.       {
  341.        netError();
  342.       }
  343.       return(FALSE);
  344.      }
  345.      break;
  346.  
  347.         // The MAIN accepting network window was closed!!!
  348.      case FD_CLOSE:
  349.      {  // This DOESNT work. And a good thing too..
  350.       //smtpSendMessage(lpClient, 221, MSG_GOODBYE_S,
  351.       //                (LPSTR)szLocalHostName);
  352.  
  353.       /* Set the window title (for debugging)  */
  354. #ifdef USE_TITLE
  355.       if(iLogLevel==LOG_HIGH)
  356.       {
  357.        wsprintf((LPSTR)szTitle, "WSMTPD - %s disconnected from port %d",
  358.                 (LPSTR)lpClient->szPeer,
  359.                 lpClient->saPeer.sin_port);
  360.        SetWindowText(hWndDlg, (LPSTR)szTitle);
  361.       }
  362. #endif /* USE_TITLE */
  363.  
  364.         // Hasta la Vista, Baby
  365.       smtpDestroyClient(lpClient);
  366.       return(FALSE);
  367.      }
  368.      break;
  369.  
  370.         // Shouldn't get to here!!!
  371.      default:
  372.      {
  373.       netError();
  374.       return(FALSE);
  375.      }
  376.     }
  377.    } /* NET_ACCEPT */
  378.    break;
  379.  
  380.    // Get the peer's name - No spoofing allowed in this server!
  381.    // gethostbyname() doesn't seem to block much anyway
  382.    //   so it's a decent compromise.
  383. /*   case NET_NAME:
  384.    {
  385.     DEBUGIT("NET_NAME Event!");
  386.     if(WSAGETASYNCERROR(lParam))
  387.     {
  388.      lstrcpy((LPSTR)lpClient->szPeer,
  389.              (LPSTR)STRING_UNKNOWN);
  390.     }
  391.     else // We found a name!!!!
  392.     {
  393.      lstrcpy((LPSTR)lpClient->szPeer,
  394.             (LPSTR)((HOSTENT*)(lpClient->hePeer))->h_name);
  395.     }
  396.  
  397.     smtpLog(LOG_CONNECT_S, (LPSTR)lpClient->szPeer);
  398.    }
  399.    break; /**/
  400.   } /* Msg*/
  401.  } /* if(index) */
  402.  
  403.  switch(Msg)
  404.  {
  405.   case WM_CLOSE:
  406.   { // A WSACleanup() here, and a WSACleanup() there....
  407.    smtpDestroyClient(smtpClientsHead);
  408.    smtpClientsHead=NULL;
  409.    WSACleanup();
  410.   } break;
  411.  
  412.   default:
  413.   {
  414.     // Something has to handle the other messages!
  415.    return(DefWindowProc(hWnd, Msg, wParam, lParam));
  416.   }
  417.  }
  418. } /* NetProc() */
  419.  
  420.  
  421. /* int netGetTimeAndDate(LPSTR, int);
  422.     Purpose: To format the current system time/data into a passed
  423.              buffer.
  424.              Doesn't formats the output to what other SMTP servers
  425.              report - uses the ctime() call.
  426.     Given:   String buffer pointer, and size of the buffer
  427.     Returns: TRUE if an error occurs, false otherwise
  428.     Notes:   Version 1.0 uses DOS time functions. The Windows ones
  429.              are undocumented.
  430. */
  431. BOOL netGetTimeAndDate(LPSTR lpLine, int iLine)
  432. {
  433.  struct    tm  tmClock;
  434.  time_t        tClock;
  435.  LPSTR         lpSysTime;
  436.  char          szTemp[256];
  437.  
  438.  time(&tClock);
  439.  tmClock=*localtime(&tClock);
  440.  
  441.  if(!strftime(szTemp, sizeof(szTemp), "%a, %d %b %y %H:%M:%S %z",
  442.           &tmClock))
  443.  {
  444.   lstrcpy((LPSTR)szTemp, (LPSTR)asctime(&tmClock));
  445.   szTemp[lstrlen((LPSTR)szTemp)-1]='\0';
  446.  };
  447.  
  448.  if(lstrlen((LPSTR)szTemp)>iLine)
  449.  {
  450.   szTemp[iLine]='\0';
  451.  }
  452.  lstrcpy(lpLine, (LPSTR)szTemp);
  453.  
  454.  return(FALSE);
  455. } /* netGetTimeAndDate() */
  456.  
  457.  
  458. /* int netSendData(int);
  459.     Purpose: To send data in the appropriate FIFO buffer
  460.              Sends data, and updates the pointers to what
  461.                 was actually sent.
  462.     Given:   Client index;
  463.     Returns: Same as send()
  464.     Notes:   If smtpSendString finds stop=start, then he
  465.              should flag the fact that the buffer WAS
  466.              empty, and then call this routine to set up
  467.              sending messages!!!
  468. */
  469. int netSendData(LPSMTPCLIENT lpClient)
  470. {
  471.  LPSTR lpBuffer;
  472.  LPSTR lpLine;
  473.  int fifoStart;
  474.  int fifoStop;
  475.  int fifoWalker;
  476.  int iDest;
  477.  int iCount;
  478.  int sSocket;
  479. #ifdef USE_TITLE
  480.  char szTitle[MAXLINE];
  481. #endif /* USE_TITLE */
  482.  
  483.  sSocket = lpClient->sSocket;
  484.  
  485.  if(!lpClient) return(SOCKET_ERROR);
  486.  lpLine = (LPSTR)szMainBuffer;
  487.      /* Make things easier to deal with */
  488.  lpBuffer=lpClient->lpOutputBuffer;
  489.  fifoStart=lpClient->fifoOutputStart;
  490.  fifoWalker=fifoStart;
  491.  fifoStop=lpClient->fifoOutputStop;
  492.  
  493.  if(fifoStart==fifoStop)
  494.  {
  495.   return(0);
  496.  }
  497.  
  498.     /* Keep trying to send until buffer
  499.        is empty, or WSAEWOULDBLOCK */
  500. // do
  501. // {
  502.   iDest=0;
  503.   while(fifoWalker!=fifoStop)
  504.   {
  505.    lpLine[iDest]=lpBuffer[fifoWalker];
  506.    fifoWalker=(fifoWalker+1)%MAXSNDBUFF;
  507.    iDest++;
  508.   }
  509.  
  510.   iCount=send(sSocket, lpLine,
  511.              iDest, 0);
  512.   if(iCount==SOCKET_ERROR)
  513.   {
  514.    return(iCount);
  515.   }
  516.  
  517.   fifoWalker=(fifoStart+iCount)%MAXSNDBUFF;
  518.   lpClient->fifoOutputStart=fifoWalker;
  519.  
  520.     /* Set the window title (for debugging)  */
  521. #ifdef USE_TITLE
  522.   if(iLogLevel==LOG_HIGH)
  523.   {
  524.    wsprintf((LPSTR)szTitle, "WSMTPD - Sent: %d bytes to %s:%u",
  525.             iCount,
  526.             (LPSTR)lpClient->szPeer,
  527.             lpClient->saPeer.sin_port);
  528.    SetWindowText(hWndDlg, (LPSTR)szTitle);
  529.   }
  530. #endif /* USE_TITLE */
  531.  
  532. //  iDest -= iCount;
  533. // } while(iDest!=0);
  534.  
  535.  return(iCount);
  536. } /* netSendData */
  537.  
  538.  
  539. /* int netRecieveData(int);
  540.     Purpose: To receive data from WinSock into FIFOs
  541.              Updates the fifoStop pointer to the end of the
  542.                 new data.
  543.              If no data is waiting, or there is no more room
  544.              in the buffer, this routine returns like recv().
  545.     Given:   Client index.
  546.     Returns: same as recv();
  547. */
  548. int netReceiveData(LPSMTPCLIENT lpClient)
  549. {
  550.  LPSTR lpBuffer;
  551.  LPSTR lpLine;
  552.  int fifoStart;
  553.  int fifoStop;
  554.  int fifoWalker;
  555.  int iMax;
  556.  int iDest;
  557.  int iCount;
  558.  int sSocket;
  559. #ifdef USE_TITLE
  560.  char szTitle[MAXLINE];
  561. #endif /* USE_TITLE */
  562.  
  563.  sSocket = lpClient->sSocket;
  564.  lpLine = (LPSTR)szMainBuffer;
  565.  iMax=lpClient->iInputSize;
  566.  
  567.  fifoStart=lpClient->fifoInputStart;
  568.  fifoStop=lpClient->fifoInputStop;
  569.  
  570.     // Calculate the room we have ready
  571.     // szMainBuffer can be a bottleneck if the Receive buffer is big
  572.  if(fifoStop<fifoStart) iDest=min( (fifoStart-fifoStop),
  573.                                    sizeof(szMainBuffer) );
  574.  else if(fifoStart<=fifoStop) iDest=min( (iMax-fifoStop+fifoStart),
  575.                                          sizeof(szMainBuffer) );
  576.     // The min() hack was so that we don't get more data than we
  577.     // are ready to handle.
  578.  
  579.  lpBuffer=lpClient->lpInputBuffer;
  580.  
  581.     /* There is room at the end! Copy it in! */
  582.     /* Tell winsock to release it first, tho */
  583.  iCount=recv(sSocket, lpLine,
  584.              iDest, 0);
  585.  
  586.     /* Set the window title (for debugging)  */
  587. #ifdef USE_TITLE
  588.  if(iLogLevel==LOG_HIGH)
  589.  {
  590.   if(iCount!=SOCKET_ERROR)
  591.   {
  592.    wsprintf((LPSTR)szTitle, "WSMTPD - Received: %d bytes from %s:%u",
  593.             iCount,
  594.             (LPSTR)lpClient->szPeer,
  595.             lpClient->saPeer.sin_port);
  596.    SetWindowText(hWndDlg, (LPSTR)szTitle);
  597.   }
  598.   else
  599.   {
  600.    if((WSAGetLastError()!=WSAENOTCONN)&&
  601.       (WSAGetLastError()!=WSAEINPROGRESS))
  602.    {
  603.     wsprintf((LPSTR)szTitle, "WSMTPD - SOCKET_ERROR #%d from %s:%u",
  604.             WSAGetLastError(),
  605.             (LPSTR)lpClient->szPeer,
  606.             lpClient->saPeer.sin_port);
  607.     SetWindowText(hWndDlg, (LPSTR)szTitle);
  608.    }
  609.   }
  610.  }
  611. #endif /* USE_TITLE */
  612.  
  613.  if(iCount==SOCKET_ERROR)
  614.  {  // If something was blocking, always try again
  615.   return(iCount);
  616.  }
  617.  if(iCount==0) return(iCount);
  618.  
  619.  iDest=0;
  620.  fifoWalker=fifoStop;
  621.  while(iDest<iCount)
  622.  {
  623.   lpBuffer[fifoWalker]=lpLine[iDest];
  624.   fifoWalker=(fifoWalker+1)%iMax;
  625.   iDest++;
  626.  }
  627.  
  628.  lpClient->fifoInputStop=fifoWalker;
  629.  return(iCount);
  630. } /* netReceiveData */
  631.  
  632.  
  633. #endif /* NET_C */
  634.  
  635.